
#pragma once

// -----------------------------------------------------------------------------

#include "Win32.Diagnostics.Log.h"
#include "Win32.IO.MapFile.h"
#include "Win32.Text.Parse.h"
#include "Win32.Drawing.Vectors.h"

namespace Kif
{
namespace Win32
{
namespace Drawing
{
namespace AutoCad
{

namespace TxtParse = Kif::Win32::Text;

class DfxReader
{
private:

   // --------------------------------------------------------------------------
   // support for sections

   static const int maxNumericLength = 20;
   static const int maxNameLength    = 128;
   static const int maxSections      = 7;
   static const int maxEntities      = 2;

   static const int sectionHeader    = 0;
   static const int sectionClasses   = 1;
   static const int sectionTables    = 2;
   static const int sectionBlocks    = 3;
   static const int sectionEntities  = 4;
   static const int sectionObjects   = 5;
   static const int sectionThumbNailImage  = 6;

   static const int entityLine      = 0;

   Kif::Win32::IO::MapFile<char> dfxBuffer;

   typedef char *(DfxReader::*ParseHandler)(char *);
   typedef struct Item
   {
      int   ItemIndex;
      char *Identifier;
      int   IdLength;
      char *Buffer;

      ParseHandler funcHandler;
   }  ;

   Item sections[maxSections];
   Item entities[maxEntities];

   char currentItemName[maxNameLength+1];
   Kif::Win32::Drawing::Vectors vectorSet;

   // --------------------------------------------------------------------------
   // support for format keywords

   typedef struct Keywords
   {
      char *Section;
      char *EndSection;
      char *Header;
      char *Classes;
      char *Tables;
      char *Blocks;
      char *Entities;
      char *Objects;
      char *ThumbNailImage;
      char *AcDbEntity;

      static const int SectionLength    = 7;
      static const int EndSectionLength = 6;
      static const int HeaderLength     = 6;
      static const int ClassesLength    = 7;
      static const int TablesLength     = 6;
      static const int BlocksLength     = 6;
      static const int EntitiesLength   = 8;
      static const int ObjectsLength    = 7;

      static const int ThumbNailImageLength = 14;

      static bool Compare(char *source, char *string)
      {
         if (string == NULL)
            return(false);

         while ((*source != NULL) && (*source == *string))
         {
            source++;
            string++;
         }
         return(*source == NULL);
      }

      Keywords()
      {
         Section    = "SECTION";
         EndSection = "ENDSEC";
         Header     = "HEADER";
         Classes    = "CLASSES";
         Tables     = "TABLES";
         Blocks     = "BLOCKS";
         Entities   = "ENTITIES";
         Objects    = "OBJECTS";
         ThumbNailImage = "THUMBNAILIMAGE";
         AcDbEntity = "AcDbEntity";
      }

   }  ;

   Keywords keys;

   // --------------------------------------------------------------------------
   // support to parse document

   inline char *IsSection(char *buff)
   {
      if ((*buff == '0') && (TxtParse::Parse::IsDelimeter(buff+1)))
      {
         char *bf = buff + 3;
         if (keys.Compare(keys.Section,bf))
         {
            bf += keys.SectionLength;
            // reposition cursor in following token
            bf += 7; // eat: 0x0d 0x0a sp sp 2 0x0d 0x0a (7 char)
         }
         else
            return NULL;
         return bf;
      }
      return NULL;
   }  // end of IsSection

   inline char *GetItem(char *itemId, int itemLength,
      char *outBuff, int outBuffLength, char *buff)
   {
      *outBuff = NULL;
      if (buff == NULL)
         return(NULL);

      if (Keywords::Compare(itemId,buff))
      {
         buff += itemLength + 2; // <item> cr lf
         // stuff item in buffer
         buff = TxtParse::Parse::GetToken(outBuff,outBuffLength,buff);
      }
      else
         return NULL;
      return(buff);
   }

   Item *GetNextSection(char *buff);

   char *ParseHeader(char *buff);
   char *ParseClasses(char *buff);
   char *ParseTables(char *buff);
   char *ParseBlocks(char *buff);
   char *ParseEntities(char *buff);
   char *ParseObjects(char *buff);
   char *ParseThumbNailImage(char *buff);

   char *ParseEntityHandle(char *buff);
   char *ParseEntityType(char *buff,char *expectedBuffer);
   char *ParseEntityLayerName(char *buff);
   char *ParseEntityGetNumberOfVertices(char *buff, long *numVertices);
   char *ParseEntityIsPolyLineClose(char *buff, bool *isClosed);
   char *ParseEntityLineType(char *buff, int *pLineType);

   char *ParseEntityLine(char *buff);
   char *ParseEntityPolyLine(char *buff);

   // --------------------------------------------------------------------------

   Kif::Win32::String *pOutputFilePath;

   void CloseOutput()
   {
      if (pOutputFilePath)
      {
         vectorSet.FileClose();
         delete pOutputFilePath;
         pOutputFilePath = NULL;
      }
   }

public:

   Kif::Win32::Diagnostics::Verbosity Verbosity;

   bool Open(TCHAR *filePath);
   void Close();
   void Parse();

   void SetOutputFilePath(TCHAR *pFilePath)
   {
      if (pFilePath)
      {
         pOutputFilePath = new Kif::Win32::String();
         pOutputFilePath->Copy(pFilePath);
         vectorSet.FileOpen(pOutputFilePath->GetBuffer());
      }
   }

   DfxReader();
  ~DfxReader()
   {
      CloseOutput();
   }

}  ;  // end of DfxReader

}  // end of Kif.Drawing.AutoCad
}  // end of Kif.Drawing
}  // end of Kif.Win32
}  // end of Kif namespace

